package cn.k7g.alloy.autoconfiguration;

import cn.k7g.alloy.annotation.AlloyContent;
import cn.k7g.alloy.contants.AlloyConstant;
import cn.k7g.alloy.core.objectmapper.AlloyAnnotationIntrospector;
import cn.k7g.alloy.core.objectmapper.AlloyContentDeserializer;
import cn.k7g.alloy.core.objectmapper.AlloyContentSerializer;
import cn.k7g.alloy.expose.AlloyContentHandler;
import cn.k7g.alloy.expose.DefaultRestExceptionResponseHandler;
import cn.k7g.alloy.expose.WebExceptionResponseHandler;
import cn.k7g.alloy.ioc.DefaultAlloyContentHandler;
import cn.k7g.alloy.ioc.processor.EnhanceAlloyConversionServiceProcess;
import cn.k7g.alloy.mold.MoldConfig;
import cn.k7g.alloy.mold.MoldService;
import cn.k7g.alloy.mold.impl.SpelMoldService;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.annotation.Role;
import org.springframework.context.annotation.Scope;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

/**
 * 自动配置类
 * @author victor-wu
 * @date 2024年4月3日
 */
@Configuration
@ComponentScan("cn.k7g.alloy.ioc")
public class AlloyAutoConfigurationInit implements ImportAware {


    @Nullable
    protected AnnotationAttributes enableAlloy;

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanPostProcessor enhanceAlloyConversionServiceProcess() {
        return new EnhanceAlloyConversionServiceProcess();
    }

    @Bean
    @ConditionalOnMissingBean(WebExceptionResponseHandler.class)
    public WebExceptionResponseHandler webExceptionResponseHandler() {
        return new DefaultRestExceptionResponseHandler();
    }

    @Bean(AlloyContentHandler.DEFAULT_BEAN_NAME)
    @ConditionalOnMissingBean(AlloyContentHandler.class)
    public AlloyContentHandler alloyContentHandler() {
        return DefaultAlloyContentHandler.INSTANCE;
    }

    @Bean
    @ConditionalOnMissingBean(AlloyAnnotationIntrospector.class)
    public AlloyAnnotationIntrospector alloyAnnotationIntrospector() {
        return new AlloyAnnotationIntrospector();
    }


    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @ConditionalOnMissingBean(AlloyContentSerializer.class)
    public AlloyContentSerializer alloyContentSerializer(AlloyContent content) {
        return new AlloyContentSerializer(content);
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @ConditionalOnMissingBean(AlloyContentDeserializer.class)
    public AlloyContentDeserializer alloyContentDeserializer(AlloyContent alloyContent, Class dataType) {
        return new AlloyContentDeserializer(alloyContent, dataType);
    }


    @Bean
    @ConditionalOnMissingBean(value = MoldService.class, name = AlloyConstant.BEAN_NAME_MOLD_SERVICE)
    public MoldService moldService() {
        return new SpelMoldService();
    }

    @Bean
    @ConfigurationProperties(prefix = "alloy.mold")
    public MoldConfig moldConfig() {
        return new MoldConfig();
    }


    protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
        String name = getAnnotationClass().getName();
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
        Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
                + " annotated with " + ClassUtils.getShortName(name) + "?");
        return attributes;
    }

    protected Class<?> getAnnotationClass() {
        return EnableAlloyAutoConfiguration.class;
    }

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        this.enableAlloy = AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(getAnnotationClass().getName(), false));
    }


}
